<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">

    <title>打散文字随机浮动特效</title>
</head>

<body>
<article>
    <p id="text">
        流水像清得没带半颗沙
        前身被搁在上游风化
        但那天经过那条堤坝
        斜阳又返照闪一下
        遇上一朵落花
        相遇就此拥着最爱归家
        生活别过份地童话化
        故事假使短过这五月落霞
        没有需要惊诧
        流水很清楚惜花这个责任
        真的身份不过送运
        这趟旅行若算开心
        亦是无负这一生
        水点蒸发变做白云
        花瓣飘落下游生根
        淡淡交会过各不留下印
        流水在山谷下再次分岔
        情感渐化做淡然优雅
        自觉心境已有如明镜
        为何为天降的稀客
        泛过一点浪花
        天下并非只是有这朵花
        不用为故事下文牵挂
        要是彼此都有些既定路程
        学会洒脱好吗
        流水很清楚惜花这个责任
        真的身份不过送运
        这趟旅行若算开心
        亦是无负这一生
        水点蒸发变做白云
        花瓣飘落下游生根
        命运敲定了要这么发生
        讲分开可否不再
        用憾事的口吻
        习惯无常才会庆幸
        讲真天涯途上谁是客
        散席时怎么分
        流水很清楚惜花这个责任
        真的身份不过送运
        这趟旅行若算开心
        亦是无负这一生
        水点蒸发变做白云
        花瓣飘落下游生根
        淡淡交会过各不留下印
        但是经历过最温柔共振
    </p>
    <button id="btn">放松一下</button>
</article>
</body>

</html>

<style>
    * {
        margin: 0;
        padding: 0;
    }

    body {
        background-color: #000;
        overflow: hidden;
    }

    #text {
        color: #fff;
        font-size: 20px;
        width: 80vw;
        line-height: 1.5;
        margin: 100px auto;
    }

    #btn {
        width: 150px;
        height: 50px;
        border: 1px solid #fff;
        background: #000;
        color: #fff;
        font-size: 20px;
        outline: none;
        cursor: pointer;
        border-radius: 8px;
        display: block;
        margin: 0 auto;
    }
</style>
<!-- 引入插件 -->
<script>

    function Neontext(n) {
        var e = document.getElementById(n), o = e.innerText.split(""), t = this;
        window;
        this.resetTime = 10, this.color = ["#f44336", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#2196f3", "#03a9f4", "#00bcd4", "#009688", "#4caf50", "#8bc34a", "#cddc39", "#ffeb3b", "#ffc107", "#ff9800", "#ff5722", "#795548", "#9e9e9e", "#607d8b"], this.randomColor = function () {
            var n = Math.floor(this.color.length * Math.random());
            return this.color[n]
        }, this.posRangencala = function () {
            return e.hasAttribute("ele-range") ? {
                minRange: {x: e.offsetLeft, y: e.offsetTop},
                maxRange: {x: e.offsetLeft + e.offsetWidth, y: e.offsetTop + e.offsetHeight}
            } : {
                minRange: {x: 0, y: 0},
                maxRange: {x: document.documentElement.clientWidth, y: document.documentElement.clientHeight}
            }
        }, this.spanArr = function () {
            e.innerHTML = "";
            var n = [];
            return o.forEach(function (o, s) {
                var a = document.createElement("span");
                a.style.textShadow="0 0 5px cyan, 0 0 10px magenta, 0 0 15px yellow"
                a.style.display = "inline-block", a.innerHTML = o, a.style.position = "relative", a.style.zIndex = e.hasAttribute("ele-range") ? "1" : "-1", a.style.color = t.randomColor(), a.own = {
                    pos: {
                        x: 0,
                        y: 0
                    }, ran: {x: -.5 + Math.random(), y: -.5 + Math.random()}, speed: {x: 1, y: 1}, dir: {x: 1, y: 1}
                }, e.appendChild(a), n.push(a)
            }), n
        }(), this.spanOrigin = function () {
            this.spanArr.forEach(function (n, e) {
                n.own.realPos = {
                    minx: n.offsetLeft,
                    maxx: n.offsetLeft + n.offsetWidth,
                    miny: n.offsetTop,
                    maxy: n.offsetTop + n.offsetHeight
                }
            }), this.posRangen = this.posRangencala()
        }, this.spanOrigin(), this.resetpos = function () {
            this.spanOrigin(), console.log(e + "====" + this.spanArr[0].own.pos.x + "====" + this.posRangen.maxRange.x), this.spanArr.forEach(function (n, e) {
                n.own.realPos.minx + n.own.pos.x < t.posRangen.minRange.x && (n.own.pos.x = 0), n.own.realPos.maxx + n.own.pos.x > t.posRangen.maxRange.x && (n.own.pos.x = 0), n.own.realPos.miny + n.own.pos.y < t.posRangen.minRange.y && (n.own.pos.y = 0), n.own.realPos.maxy + n.own.pos.y > t.posRangen.maxRange.y && (n.own.pos.y = 0)
            })
        }, this.floatText = function () {
            this.spanArr.forEach(function (n, e) {
                (n.own.realPos.minx + n.own.pos.x < t.posRangen.minRange.x || n.own.realPos.maxx + n.own.pos.x > t.posRangen.maxRange.x) && (n.own.dir.x = -n.own.dir.x), (n.own.realPos.miny + n.own.pos.y < t.posRangen.minRange.y || n.own.realPos.maxy + n.own.pos.y > t.posRangen.maxRange.y) && (n.own.dir.y = -n.own.dir.y), n.own.pos.x += n.own.ran.x * n.own.speed.x * n.own.dir.x, n.own.pos.y += n.own.ran.y * n.own.speed.y * n.own.dir.y, n.style.transform = "translateX(" + n.own.pos.x + "px) translateY(" + n.own.pos.y + "px)"
            })
        }, this.floatBack = function () {
            if (this.spanArr.forEach(function (n, e) {
                var o = n.own.pos.x - n.own.pos.x * t.resetTime / 100,
                    s = n.own.pos.y - n.own.pos.y * t.resetTime / 100;
                n.style.transform = "translateX(" + o + "px) translateY(" + s + "px)"
            }), 100 === this.resetTime) return cancelAnimationFrame(t.send), !0;
            this.resetTime += 5
        }, this.restart = function () {
            this.spanArr.forEach(function (n, e) {
                n.own.pos.x = 0, n.own.pos.y = 0
            })
        }, this.render = {
            run: function () {
                t.sren = requestAnimationFrame(t.render.run), t.floatText()
            }, end: function () {
                t.send = requestAnimationFrame(t.render.end), t.floatBack()
            }, killer: function () {
                t.floatBack() ? (cancelAnimationFrame(t.send), t.restart(), t.resetTime = 1000, t.render.run()) : (cancelAnimationFrame(t.sren), t.render.end())
            }
        }, window.onresize = function () {
            t.resetpos()
        }
    }

    // 要操作的元素
    // 按钮
    const resetBtn = document.getElementById('btn');
    // 初始化
    const neontext = new Neontext('text');
    // 打乱文字
    neontext.render.run();

    // 为按钮绑定点击事件
    resetBtn.addEventListener('click', function () {
        // 文字恢复
        neontext.render.killer();
    })
</script>